#ifndef LUA_SCRIPTLOGIC_H_
#define LUA_SCRIPTLOGIC_H_

#include "NonCopyable.h"
#include "ScriptLogic.h"

#include "parsers/tinyxml.h"

extern "C"
{
   #include "lua.h"

   #include "lauxlib.h"

   #include "lualib.h"

}

namespace EntitySystem
{

class LuaScriptLogic : public ScriptLogic
{
    const static int N_METHODS = 7;
    
    const static char *METHOD_TABLE[];

  
private:
    lua_State *m_context;
    
    bool m_methodDefinitions[N_METHODS];
    
    
protected:
    
    std::string m_name;
    
public:
    
    LuaScriptLogic(const std::string& scriptPath);
    
    
    ~LuaScriptLogic();
      
    
    /**
     * These logic should not be cloned or copied, thus the invocation
     * of Clone should throw an exception.
     */
    
    virtual ScriptLogic *Clone();
    
    
    /**
     * Executes the Initialize function from script.
     */
    
    void ExecuteInitialize();
    
    
    /**
     * Executes the Update function from script.
     */
    
    void ExecuteUpdate();
    
    
    /**
     * Executes the OnTileCollision function from script.
     *
     * @param tile: string that indicates the type of the tile that collided with the script owner.
     * @param contactNormal: vector indicating the direction of the collision relative to the owner
     *                       of this script.
     */
    
    void ExecuteOnTileCollision(std::string* tile, Math::Vector2F& contactNormal); 
    
    
    /**
     * Executes the OnEntityCollision function from script.
     *
     * @param collided: entity that collided with the owner of this script.
     * @param contactNormal: vector indicating the direction of the collision relative
     *                       to the owner of this script.
     */
    
    void ExecuteOnEntityCollision(Entity* collided, Math::Vector2F& contactNormal);
    
    
    /**
     * Executes the OnKeyButtonDown function from script.
     *
     * @param key: key pressed.
     * @param mod: modifiers applied to the key pressed.
     * @param association: association to the key+modidiers.
     */
    
    void ExecuteOnKeyButtonDown(Key key, KeyMod mod, std::string& association);
    
    
    /**
     * Executes the OnKeyButtonUp function from script.
     *
     * @param key: key released.
     * @param mod: modifiers applied to the key released.
     * @param association: association to the key+modidiers.
     */
    
    void ExecuteOnKeyButtonUp(Key key, KeyMod mod, std::string& association) ;
    
    
    /**
     * Executes the OnDeath function from script.
     */
    
    void ExecuteOnDeath();
    
    
    /**
     * Sets the parent of this script logic. Adds a global Entity object to the lua 
     * context named "this".
     */
    
    void SetParent(Entity *parent);
    
    
    /**
     * Returns the file name of this script logic. 
     */
    
    const char* GetName();
    
    
    /**
     * Pushes a number variable to the script logic's state.
     * 
     * @param name: name of the variable.
     * @Param value: initial value of the variable
     */
 
    template <class NumType>
    void PushNumber(const std::string& name, NumType value)
    {
	lua_pushnumber( m_context, value );
	
	lua_setglobal( m_context, name.c_str( ) );
    }
    
    
    /**
     * Pushes a string object to the script logic's state.
     *
     * @param name: name of the object's reference.
     * @param value: value of the object.
     */
    
    virtual void PushString(const std::string& name, const std::string& value);
    
    /**
     * Pushes an object reference to the script logic's state.
     *
     * @param name: name of the reference.
     * @param object: object to push.
     * @param type: type of the object given as a string.
     * @param engineManaged: true if the object is managed by the engine, false otherwise.
     */
    
    virtual void PushObject(const std::string& name, void* object, const std::string& type, bool engineManaged = true);

private:
    
    /**
     * Opens the Lua context , loads the chunk of code specified and opens the lua modules needed
     * by the scripting enivornment.
     */
    
    void Initialize(const std::string& scriptPath);
    
    
    /**
     * Checks which functions have been defined in a lua script.
     */
    
    void CheckMethodDefinitions();
    
    
   /**
    * Prints an error occurred when executing a script function. 
    *
    * @param methodIndex: index (in METHOD_TABLE) of the function that failed to execute.
    * @param errorCode: error code returned by lua.
    */
    
    void PrintExecError(int methodIndex, int errorCode);
    
    
protected:
    
    /**
     * Default constructor, initializes the lua context to null.
     */
    
    LuaScriptLogic();
};

};


#endif